#include "timer9.h"
#include <cassert>

using namespace hw;

void Timer9::init() {
  RCC->APB2ENR |= RCC_APB2ENR_TIM9EN; // enable timer clock
}

void Timer9::await(uint16_t prescale, uint16_t autoreload) {
  NVIC_DisableIRQ(TIM1_BRK_TIM9_IRQn); // enable interrupt
  // 8M * delay = (prescale + 1)  * (autoreload + 1);
  TIM9->CR1 |= (1 << 2); // Update request source: Only counter overflow
                         // generates an update interrupt if enabled
  TIM9->PSC = prescale;
  TIM9->ARR = autoreload;
  TIM9->EGR |=
      1; // Re-initializes the counter and generates an update of the registers
  TIM9->DIER |= 1;        // update interrupt enable
  TIM9->SMCR &= ~(0b111); // disable slave mode, use internal clock source
  TIM9->CNT = 0;          // reset counter value
  TIM9->SR = 0;           // clear status
  TIM9->CR1 |= 1;         // counter enable
  NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); // enable interrupt
}

void Timer9::reset(uint16_t prescale) {
  TIM9->PSC = prescale;
  TIM9->ARR = 0xffff;
  TIM9->DIER &= ~1; // update interrupt disable
  TIM9->EGR |=
      1; // Re-initializes the counter and generates an update of the registers
  TIM9->CNT = 0;    // reset counter value
  TIM9->SR = 0;     // clear status
  TIM9->CR1 |= 0b1; // counter enable
}

void Timer9::cancel() {
  TIM9->CR1 &= ~1; // counter disable
}

extern "C" {

void TIM1_BRK_TIM9_IRQHandler(void) {
  TIM9->SR &= ~1;   // clear interrupt flag
  TIM9->DIER &= ~1; // disable further interrupts
  TIM9->CR1 &= ~1;  // counter disable
  tim1_brk_tim9_irq_handler_backend();
}
}
